CLASSES IN JAVASCRIPT
This note explains classes in simple language.
Classes are used when we need to create many similar objects with the same structure, the same properties, and the same methods, but with different values. Instead of creating each object manually, we create one class and then create many objects from it.
1. Why classes are needed
An object literal is useful when we want to create one object.
Example
const user = {
name: "Aaron",
email: "exemple@nikitagoluban.eu",
};
But in real programs we often need many similar objects:
- many users
- many products
- many posts
- many employees
If we create all of them manually, the code becomes repetitive. That is why classes are used.
Diagram 1. Why classes exist
One object
↓
object literal is enough
Many similar objects
↓
use a class
2. Declaring a class
A class is declared with:
- the
classkeyword - the class name
- the class body inside curly braces
Example
class User {
// Class body
}
Class names usually begin with a capital letter. This helps us quickly see that this is a class.
Diagram 2. Class structure
class User {
// body
}
class → keyword
User → class name
{ } → class body
3. Creating an instance from a class
After a class is declared, we can create an object from it using the new operator. An object created from a class is called an instance.
Example
class User {}
const aaron = new User();
console.log(aaron); // {}
const benjamin = new User();
console.log(benjamin); // {}
Explanation
Here:
Useris the classaaronis an instance ofUserbenjaminis another instance ofUser
Diagram 3. Class and instances
class User
↓
new User()
↓
instance object
4. Constructor
A class uses a special method called constructor to initialize new objects. When we call new User(...), JavaScript automatically creates a new object and calls the constructor.
Example
class User {
constructor(name, email) {
console.log(name, email);
}
}
const aaron = new User("Aaron", "exemple@nikitagoluban.eu");
The values passed into new User(...) become arguments for the constructor.
5. this inside the constructor
Inside the constructor, this refers to the object that is currently being created. That is why we use this to save values into the new object.
Example
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
}
const aaron = new User("Aaron", "exemple@nikitagoluban.eu");
console.log(aaron); // { name: "Aaron", email: "exemple@nikitagoluban.eu" }
const benjamin = new User("Benjamin", "exemple2@nikitagoluban.eu");
console.log(benjamin); // { name: "Benjamin", email: "exemple2@nikitagoluban.eu" }
Diagram 4. Constructor work
new User("Aaron", "exemple@nikitagoluban.eu")
↓
constructor(name, email)
↓
this.name = "Aaron"
this.email = "exemple@nikitagoluban.eu"
↓
new object is ready
6. Public properties
Properties like name and email in the example above are called public properties. They belong directly to the object, and we can access them from outside the class.
Example
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
}
const aaron = new User("Aaron", "exemple@nikitagoluban.eu");
console.log(aaron.name); // "Aaron"
console.log(aaron.email); // "exemple@nikitagoluban.eu"
Diagram 5. Public properties
aaron
│
├─ name: "Aaron"
└─ email: "exemple@nikitagoluban.eu"
7. Parameter object pattern
Sometimes a class needs many values. Instead of passing many separate arguments, we can pass one object with named properties. This is called the parameter object pattern.
Example
class User {
constructor(params) {
this.name = params.name;
this.email = params.email;
}
}
const aaron = new User({
name: "Aaron",
email: "exemple@nikitagoluban.eu",
});
console.log(aaron);
Why this is useful
This style is easier to read because we immediately see what each value means.
Diagram 6. Parameter object
new User({
name: "Aaron",
email: "exemple@nikitagoluban.eu"
})
One object
↓
named values
↓
clearer constructor call
8. Class methods
A class can contain methods. These methods are used to work with the properties of the object.
Example
class User {
constructor(params) {
this.name = params.name;
this.email = params.email;
}
getEmail() {
return this.email;
}
changeEmail(newEmail) {
this.email = newEmail;
}
}
Explanation
Here:
getEmail()returns the emailchangeEmail(newEmail)changes the email
Diagram 7. Class with methods
class User
│
├─ constructor(...)
├─ getEmail()
└─ changeEmail(newEmail)
9. Using class methods
After we create an instance, we can call its methods.
Example
const aaron = new User({
name: "Aaron",
email: "exemple@nikitagoluban.eu",
});
console.log(aaron.getEmail()); // "exemple@nikitagoluban.eu"
aaron.changeEmail("exemple2@nikitagoluban.eu");
console.log(aaron.getEmail()); // "exemple2@nikitagoluban.eu"
The methods work with the properties of the object that called them.
10. Where class methods are stored
A very important point:
Class methods are not copied directly into every object.
Instead, they are stored in:
User.prototype
and objects use them through the prototype chain.
Example
class User {
constructor(params) {
this.name = params.name;
this.email = params.email;
}
getEmail() {
return this.email;
}
changeEmail(newEmail) {
this.email = newEmail;
}
}
console.log(User.prototype);
This is efficient because there is no need to copy the same method into every instance. All instances share the same prototype methods.
Diagram 8. Class → prototype → instance
class User
│
├─ constructor()
├─ getEmail()
└─ changeEmail()
│
▼
User.prototype
│
▼
new User(...) → instance
│
├─ name
└─ email
11. Encapsulation
Encapsulation means hiding the internal details of a class from outside code. Outside code should use the public interface of the class, not change everything directly.
In JavaScript, encapsulation is done with private properties and private methods.
12. Private properties
A private property starts with #.
It can be used only inside the class. Outside code cannot read it directly.
Example
class User {
name;
#email;
constructor(params) {
this.name = params.name;
this.#email = params.email;
}
}
const aaron = new User({
name: "Aaron",
email: "exemple@nikitagoluban.eu",
});
console.log(aaron.name); // "Aaron"
// console.log(aaron.#email); // Error
Explanation
nameis public#emailis private
Diagram 9. Public vs private
User instance
│
├─ name → public
└─ #email → private
13. Accessing private data through public methods
Because private properties cannot be accessed directly, we usually create public methods to work with them.
Example
class User {
name;
#email;
constructor(params) {
this.name = params.name;
this.#email = params.email;
}
getEmail() {
return this.#email;
}
changeEmail(newEmail) {
this.#email = newEmail;
}
}
const aaron = new User({
name: "Aaron",
email: "exemple@nikitagoluban.eu",
});
console.log(aaron.getEmail()); // "exemple@nikitagoluban.eu"
aaron.changeEmail("exemple2@nikitagoluban.eu");
console.log(aaron.getEmail()); // "exemple2@nikitagoluban.eu"
Diagram 10. Working with private property
Outside code
│
├─ getEmail()
└─ changeEmail(...)
│
▼
#email
14. Private methods
A private method also starts with #.
It can only be called inside the class. This is useful when you want to hide inner logic.
Example
class User {
name;
#email;
constructor(params) {
this.name = params.name;
this.#email = params.email;
}
getEmail() {
return this.#email;
}
changeEmail(newEmail) {
if (this.#validateEmail(newEmail)) {
this.#email = newEmail;
} else {
console.log("Invalid email format");
}
}
#validateEmail(email) {
return email.includes("@");
}
}
Explanation
Here:
changeEmail()is public#validateEmail()is private- outside code cannot call
#validateEmail()directly
Diagram 11. Private method
Public method:
changeEmail()
Inside it:
#validateEmail()
Outside code
↓
cannot call #validateEmail()
15. Getters and setters
Getters and setters are special methods that look like normal properties when we use them. They are convenient when we want controlled access to a value, especially a private one.
Example
class User {
#email;
constructor(params) {
this.name = params.name;
this.#email = params.email;
}
get email() {
return this.#email;
}
set email(newEmail) {
this.#email = newEmail;
}
}
Explanation
get email()runs when we readaaron.emailset email(newEmail)runs when we writeaaron.email = ...
Example of use
const aaron = new User({
name: "Aaron",
email: "exemple@nikitagoluban.eu",
});
console.log(aaron.email); // "exemple@nikitagoluban.eu"
aaron.email = "exemple2@nikitagoluban.eu";
console.log(aaron.email); // "exemple2@nikitagoluban.eu"
Diagram 12. Getter and setter
aaron.email
↓
getter runs
aaron.email = "exemple2@nikitagoluban.eu"
↓
setter runs
16. Why getters and setters are useful
Because they let us run extra logic while still using simple property syntax.
Example
set email(newEmail) {
if (newEmail === "") {
console.log("Error! Email cannot be an empty string!");
return;
}
this.#email = newEmail;
}
Now the setter protects the class from invalid values.
17. Static properties
A class can have properties that belong to the class itself, not to instances. These are called static properties.
Example
class MyClass {
static myProp = "value";
}
console.log(MyClass.myProp); // "value"
Important
Instances do not have access to static properties.
class MyClass {
static myProp = "value";
}
const inst = new MyClass();
console.log(inst.myProp); // undefined
Diagram 13. Static property
MyClass.myProp → works
instance.myProp → undefined
18. Static property example with user roles
class User {
static roles = {
admin: "admin",
editor: "editor",
basic: "basic"
};
#email;
#role;
constructor(params) {
this.#email = params.email;
this.#role = params.role || User.roles.basic;
}
get role() {
return this.#role;
}
set role(newRole) {
this.#role = newRole;
}
}
Here roles belongs to the class itself. It stores possible roles that can be used when creating objects.
19. Static methods
A class can also have methods that belong to the class itself. These are called static methods.
Example
class MyClass {
static myMethod() {
console.log("A static method");
}
}
MyClass.myMethod();
Static methods are called on the class, not on instances.
20. Static method example
class User {
static #takenEmails = [];
static isEmailTaken(email) {
return User.#takenEmails.includes(email);
}
#email;
constructor(params) {
this.#email = params.email;
User.#takenEmails.push(params.email);
}
}
const aaron = new User({ email: "exemple@nikitagoluban.eu" });
console.log(User.isEmailTaken("exemple2@nikitagoluban.eu")); // false
console.log(User.isEmailTaken("exemple@nikitagoluban.eu")); // true
Explanation
Here:
#takenEmailsis a static private propertyisEmailTaken()is a static method- the class uses them to track existing emails
Diagram 14. Static data and static method
User class
│
├─ static #takenEmails
└─ static isEmailTaken()
Instances
↓
do not access these directly
21. Inheritance
Inheritance allows one class to use the properties and methods of another class.
For this, JavaScript uses:
extends
Example
class Parent {}
class Child extends Parent {}
This means Child inherits from Parent.
Why inheritance is useful
It helps avoid repeating common code.
22. Example of inheritance with User and ContentEditor
class User {
#email;
constructor(email) {
this.#email = email;
}
get email() {
return this.#email;
}
set email(newEmail) {
this.#email = newEmail;
}
}
class ContentEditor extends User {}
const editor = new ContentEditor("exemple@nikitagoluban.eu");
console.log(editor.email); // "exemple@nikitagoluban.eu"
ContentEditor inherits from User, so it gets the email logic from the parent class.
23. Child class constructor and super()
If a child class has its own constructor, it must call:
super(...)
inside that constructor. super(...) calls the parent constructor.
Example
class User {
#email;
constructor(email) {
this.#email = email;
}
get email() {
return this.#email;
}
set email(newEmail) {
this.#email = newEmail;
}
}
class ContentEditor extends User {
constructor(params) {
super(params.email);
this.posts = params.posts;
}
}
const editor = new ContentEditor({
email: "exemple@nikitagoluban.eu",
posts: []
});
console.log(editor.email); // "exemple@nikitagoluban.eu"
console.log(editor.posts); // []
Explanation
Here:
super(params.email)sends the email to the parent constructor- then the child class adds its own property
posts
Diagram 15. Child constructor
ContentEditor constructor
│
├─ super(params.email)
│ ↓
│ User constructor runs
│
└─ this.posts = params.posts
24. Child class methods
A child class can also add its own methods.
Example
class ContentEditor extends User {
constructor(params) {
super(params.email);
this.posts = params.posts;
}
addPost(post) {
this.posts.push(post);
}
}
Example of use
const editor = new ContentEditor({
email: "exemple@nikitagoluban.eu",
posts: []
});
editor.addPost("post-1");
editor.addPost("post-2");
console.log(editor.posts); // ["post-1", "post-2"]
Explanation
Here:
ContentEditorgets common logic fromUserContentEditoradds its own propertypostsContentEditoradds its own methodaddPost()
Diagram 16. Inheritance structure
User
│
├─ #email
├─ get email()
└─ set email()
│
▼
ContentEditor extends User
│
├─ posts
└─ addPost()
25. Easy memory rules
Class = blueprint
Instance = real object created from the class
Constructor = special method for creating the object
Public property = accessible from outside
Private property = hidden inside class
Getter/Setter = controlled access to a value
Static = belongs to the class, not to instances
Inheritance = child class reuses parent logic
26. Quick summary
- A class is used to create many similar objects.
newcreates an instance from a class.constructorinitializes the object.thisinside the constructor refers to the new object.- Methods are shared through
prototype. - Private fields and methods begin with
#. - Getters and setters provide controlled access to values.
- Static properties and methods belong to the class itself.
extendscreates inheritance.super()calls the parent constructor.
27. Final conclusion
Classes help organize code in a clear and powerful way.
If you understand these ideas:
Class
Constructor
Methods
Public and private data
Getters and setters
Static properties and methods
Inheritance
then you already have a strong foundation for object-oriented programming in JavaScript.